/* file nd_instance.cpp
 * define class ndCInstance
 * 
 * all right reserved by neil duan
 *
 * 2009-4-24 22:41
 */

#ifdef WIN32
#ifdef ND_DEBUG
#pragma comment(lib,"nd_srvcore_dbg.lib")
#pragma comment(lib,"nd_net_dbg.lib")
#pragma comment(lib,"nd_crypt_dbg.lib")
#pragma comment(lib,"nd_common_dbg.lib")

#else 
#pragma comment(lib,"nd_srvcore.lib")
#pragma comment(lib,"nd_net.lib")
#pragma comment(lib,"nd_crypt.lib")
#pragma comment(lib,"nd_common.lib")
#endif

#pragma comment(lib,"Ws2_32.lib")
#include <conio.h>
#endif

#include "nd_common/nd_common.h"
#include "nd_app/nd_app.h"

#include "nd_appcpp/nd_instance.h"

#include "nd_appcpp/nd_cmmgr.h"
#include "nd_appcpp/nd_listener.h"
#include "nd_appcpp/nd_session.h"
//#include "nd_appcpp/nd_allocator.h"

//extern NDINT32 create_stl_allocator() ;
//extern  void destroy_stl_allocator() ;

NDINT8 *NDInstanceSrv::config_file = NULL;

srv_config NDInstanceSrv::srvcfg ={0};

#define HANDLE_UNIX_SIGNAL 1        //handle unix signal

NDInstanceSrv::NDInstanceSrv() 
{
	tminterval = 100 ;
	pListen = 0;
	timer_thid = 0 ;
}

NDInstanceSrv::~NDInstanceSrv() 
{

}

NDINT32 NDInstanceSrv::InitApp(NDINT32 argc, NDINT8 *argv[])
{
	NDINT32 i ;
#define INIT_MOD(name)		\
	if(-1==nd_##name##_init() ) {	\
		nd_logfatal("init " #name " error!\n") ;	\
		return -1 ;	}

	INIT_MOD(common)
	INIT_MOD(net)
	INIT_MOD(srvcore)

	//if(0!=create_stl_allocator() ) {
	//	nd_logfatal("create mempool for stl ERROR\n") ;
	//}

	
#ifndef WIN32
#ifdef  HANDLE_UNIX_SIGNAL
	block_signal() ;
#endif 
#endif	
	nd_arg(argc, argv);	
	
	//get config file 	
	for (i=1; i<argc-1; i++){
		if(0 == ndstrcmp((const char *)argv[i],"-f")) {
			NDInstanceSrv::config_file = argv[i+1] ;
			break ;
		}
	}

	if(!NDInstanceSrv::config_file) {
		ndprintf("usage: -f config-file\n press ANY key to continue\n") ;
		getch() ;
		exit(1) ;
		//return -1 ;
	}
	if(-1==read_config((NDINT8 *)NDInstanceSrv::config_file, &(NDInstanceSrv::srvcfg)) ) {
		ndprintf("press ANY key to continue\n") ;
		getch() ;
		exit(1) ;
	}
	
	create_rsa_key() ;

	//set crypt function
	nd_net_set_crypt((nd_netcrypt)nd_TEAencrypt, (nd_netcrypt)nd_TEAdecrypt, sizeof(tea_v)) ;

	return 0 ;

}

void NDInstanceSrv::DestroyApp()
{
	nd_thsrv_release_all() ;
	destroy_rsa_key() ;
	
	nd_srvcore_destroy() ;
	nd_net_destroy() ;
	
	//destroy_stl_allocator() ;

	nd_common_release() ;
}

NDINT32 NDInstanceSrv::InitServer( size_t session_size)
{
	pListen = CreateListener() ;

	if(!pListen) {
		return -1 ;
	}
	
	pListen->Initilize(NDInstanceSrv::srvcfg.max_connect,
		session_size, (NDINT8 *)NDInstanceSrv::srvcfg.listen_name) ;
		
	return 0;

}

NDINT32 NDInstanceSrv::StartServer()
{
	NDINT32 ret = pListen->Open(NDInstanceSrv::srvcfg.port) ;
	if(0!=ret) {
		return ret ;
	}
//	ret = CreateTimer() ;
	return ret ;
}

NDINT32 NDInstanceSrv::WaitServer()
{
	return wait_services() ;
}

NDINT32 NDInstanceSrv::EndServer(NDINT32 force)
{
	nd_host_eixt() ;
	if(timer_thid) {
		
#ifdef SINGLE_THREAD_MOD
		nd_listensrv_del_timer(pListen->GetHandle(), timer_thid) ;
#else 
		nd_thsrv_destroy(timer_thid, force) ;
#endif 
		timer_thid = 0 ;
	}
	if(0==pListen->Close(force)) {
		DestroyListener() ;
		return 0 ;
	}

	return -1 ;
}

NDListener *NDInstanceSrv::CreateListener() 
{ 
	return new NDListener();	
}
void NDInstanceSrv::DestroyListener() 
{ 
	if(pListen){delete pListen;	 pListen = 0 ;} 
}


/* entry of  timer update client map*/
static NDINT32 _timer_func(void *param)
{
	NDSession *psession ;
	NDInstanceSrv *pinst = static_cast<NDInstanceSrv *> (param) ;

	NDCmIterator cm_it(pinst) ;
	NDOStreamMsg sendmsg(MAXID_SYS, SYM_TEST) ;
	
	if(!cm_it.CheckValid()) {
		nd_sleep(100) ;
		return 0 ;
	}
	//sendmsg << (NDINT8*) "hello world!" ;
	sendmsg.Write((NDINT8*) "hello world!" );

	for (psession=cm_it.First(); psession; psession=cm_it.Next()) {
		psession->SendMsg(sendmsg) ;
		nd_sleep(10) ;
	}
	nd_sleep(pinst->tminterval) ;
	return 0 ;
}

static NDINT32 _timer_func1(ndtimer_t tmid, void *param)
{
	NDSession *psession ;
	NDInstanceSrv *pinst = static_cast<NDInstanceSrv *> (param) ;

	NDCmIterator cm_it(pinst) ;
	NDOStreamMsg sendmsg(MAXID_SYS, SYM_TEST) ;
	
	if(!cm_it.CheckValid()) {
		return 0 ;
	}
	//sendmsg << (NDINT8*) "hello world!" ;
	sendmsg.Write((NDINT8*) "hello world!" );
//ND_RUN_HERE() ;
	for (psession=cm_it.First(); psession; psession=cm_it.Next()) {
		psession->SendMsg(sendmsg) ;
	}
	return 0 ;
}

NDINT32 NDInstanceSrv::CreateTimer(NDINT32 tmval)
{	
#ifdef SINGLE_THREAD_MOD
	return nd_listensrv_timer(pListen->GetHandle(),_timer_func1, this,tmval, ETT_LOOP) ;
#else 
	struct nd_thsrv_createinfo th_info = {
		SUBSRV_RUNMOD_LOOP,	//srv_entry run module (ref e_subsrv_runmod)
		(nd_threadsrv_entry)_timer_func,			//service main entry function address
		(void*)this,		//param of srv_entry 
		NULL ,					//handle received message from other thread!
		NULL,					//clean up when server is terminal
		_NDT("Instance_timer"),			//service name
		NULL		//user data
	};


	timer_thid = nd_thsrv_createex(&th_info, NDT_PRIORITY_LOW,0)  ;
	if(!timer_thid )
		return -1;
#endif 
	tminterval = tmval ;
	return 0 ;
}
